package com.zoro.barn.commons.db.autopage;

import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.session.Configuration;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author zhaoxingwu
 */
public class PagerUtils {
    private static final Map<String, MappedStatement> CACHED_COUNT_STATEMENT = new ConcurrentHashMap<>();

    public static MappedStatement makeCountMappedStatement(MappedStatement oldMs, String newId) {
        if (CACHED_COUNT_STATEMENT.containsKey(newId)) {
            return CACHED_COUNT_STATEMENT.get(newId);
        }
        Configuration configuration = oldMs.getConfiguration();
        MappedStatement.Builder builder = new MappedStatement.Builder(configuration, newId, oldMs.getSqlSource(), oldMs.getSqlCommandType());
        builder.cache(oldMs.getCache());
        builder.lang(oldMs.getLang());
        builder.databaseId(oldMs.getDatabaseId());
        builder.fetchSize(oldMs.getFetchSize());
        builder.flushCacheRequired(oldMs.isFlushCacheRequired());
        builder.keyGenerator(oldMs.getKeyGenerator());
        builder.parameterMap(oldMs.getParameterMap());
        builder.resource(oldMs.getResource());
        List<ResultMap> resultMaps = new ArrayList<>();
        ResultMap resultMap = new ResultMap.Builder(configuration, oldMs.getId(), Long.class,
                Collections.emptyList()).build();
        resultMaps.add(resultMap);
        builder.resultMaps(resultMaps);
        builder.resultOrdered(oldMs.isResultOrdered());
        builder.resultSets(StringUtils.join(oldMs.getResultSets(), ","));
        builder.timeout(oldMs.getTimeout());
        builder.useCache(oldMs.isUseCache());
        builder.keyProperty(StringUtils.join(oldMs.getKeyProperties(), ","));
        builder.keyColumn(StringUtils.join(oldMs.getKeyColumns(), ","));
        MappedStatement ms = builder.build();
        CACHED_COUNT_STATEMENT.put(newId, ms);
        return ms;
    }

    public static BoundSql makePageSql(BoundSql unPageSql, int limit, int offset,Configuration configuration) {
        String newSql = "select * from ( " + unPageSql.getSql() + " limit "+Integer.MAX_VALUE+" ) _original_sql limit " + offset + " , " + limit;

        return new BoundSql(configuration, newSql, unPageSql.getParameterMappings(), unPageSql.getParameterObject());
    }

    public static BoundSql makeCountSql(BoundSql unPageSql,Configuration configuration) {
        String newSql = "select count(*) from ( " + unPageSql.getSql() + "  ) _original_sql ";

        return new BoundSql(configuration, newSql, unPageSql.getParameterMappings(), unPageSql.getParameterObject());
    }
}
